﻿using Abp.Domain.Entities;
using System;
using System.Linq;
using System.Linq.Expressions;

namespace Basefr.Core.Extensions
{
    public static class QueryExtensions
    {
        public static TEntity FirstOrDefault<TEntity, TPrimaryKey>(this IQueryable<TEntity> queryable, TPrimaryKey key)
            where TEntity : IEntity<TPrimaryKey>
        {
            return queryable.FirstOrDefault(p => p.Id.Equals(key));
        }

        public static TEntity First<TEntity, TPrimaryKey>(this IQueryable<TEntity> queryable, TPrimaryKey key)
            where TEntity : IEntity<TPrimaryKey>
        {
            return queryable.First(p => p.Id.Equals(key));
        }

        /// <summary>
        /// 排序
        /// </summary>
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortExpression)
        {
            if (string.IsNullOrWhiteSpace(sortExpression))
            {
                throw new ArgumentNullException(nameof(sortExpression), "排序字段不能为空");
            }

            var parts = sortExpression.Split(' ');
            var isDescending = false;
            var tType = typeof(T);

            if (parts.Length > 0 && parts[0] != "")
            {
                var propertyName = parts[0];

                if (parts.Length > 1)
                {
                    isDescending = parts[1].ToUpper().Contains("ESC");
                }

                var prop = tType.GetProperty(propertyName);

                if (prop == null)
                {
                    throw new ArgumentException($"No property '{propertyName}' on type '{tType.Name}'");
                }

                var funcType = typeof(Func<,>).MakeGenericType(tType, prop.PropertyType);

                var lambdaBuilder = typeof(Expression).GetMethods().First(x => x.Name == "Lambda" && x.ContainsGenericParameters && x.GetParameters().Length == 2).MakeGenericMethod(funcType);

                var parameter = Expression.Parameter(tType);
                var propExpress = Expression.Property(parameter, prop);

                var sortLambda = lambdaBuilder.Invoke(null, new object[] { propExpress, new ParameterExpression[] { parameter } });

                var sorter = typeof(Queryable).GetMethods()
                    .FirstOrDefault(x => x.Name == (isDescending ? "OrderByDescending" : "OrderBy") && x.GetParameters().Length == 2)
                    ?.MakeGenericMethod(new[] { tType, prop.PropertyType });

                return (IQueryable<T>)sorter?.Invoke(null, new object[] { source, sortLambda });
            }

            return source;
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        public static IQueryable<T> GetPage<T>(this IQueryable<T> queryable, int skipCount, int pageSize, out int total, out bool isOverPaged)
        {
            total = queryable.Count();

            isOverPaged = skipCount >= total;

            if (isOverPaged)
            {
                skipCount = 0;  //如果当前页码超出数据总量，直接查询第一页
            }

            return queryable.Skip(skipCount).Take(pageSize);
        }

    }

}
